/* CCScript Value implementation */

#include "value.h"

#include "table.h"
#include "function.h"
#include "string.h"


//////////////////////////////////////////////
// Types

// Default constructor: initializes undefined type
Type::Type() : t(Undefined)
{
}

// Copy constructor: copies type from other Type object
Type::Type(const Type& other) : t(other.t)
{
}

// Constructs a type object from one of the Type enumeration constants
Type::Type(Type::EType t)
{
	this->t = t;
}

// Assigns the value of another Type to this Type
Type& Type::operator=(const Type& rhs)
{
	t = rhs.t;
	return *this;
}

// Assigns a Type enumeration constant to this Type
Type& Type::operator=(Type::EType rhs)
{
	t = rhs;
	return *this;
}


// Ccompare Type objects against other Type objects
bool Type::operator==(const Type& rhs) const
{
	return t == rhs.t;
}
bool Type::operator!=(const Type& rhs) const
{
	return !operator==(rhs);
}

// Compare Type objects against type enumeration constants
bool Type::operator==(Type::EType rhs) const
{
	return t == rhs;
}
bool Type::operator!=(Type::EType rhs) const
{
	return !operator==(rhs);
}

// Implicitly convert Type to Type::EType
//  (All this to avoid C++'s enum scope pollution!)
Type::operator EType()
{
	return t;
}





//////////////////////////////////////////////
// Values


// Default constructor:
//  Initializes an "undefined" value
Value::Value() : type()
{
}

Value::Value(int n)
	: type(Type::Number), val(n)
{
}

Value::Value(String* s)
	: type(Type::String), val(s)
{
}

Value::Value(Function* f)
	: type(Type::Function), val(f)
{
}

Value::Value(Table* t)
	: type(Type::Table), val(t)
{
}

Value::Value(Label* l)
	: type(Type::Label), val(l)
{
}

// Copy constructor
//  Creates a value that is a copy of another value. If the value
//  is a reference type, the reference count is shared and incremented.
Value::Value(const Value& other)
	: type(other.type), val(other.val)
{

}

Value::~Value()
{
	// If this value is of a reference type, decrease the reference count;
	// if the reference count drops to zero, delete the referenced object.
	Release();
}


bool Value::IsRefCounted()
{
	return type == Type::String ||
		type == Type::Function ||
		type == Type::Table;
}

void Value::Release()
{
	if(IsRefCounted()) {
		(*refcount)--;
		if(*refcount < 1) Delete();
	}
}

void Value::Delete()
{
	switch(type) {
		case Type::String:
			delete val.string;
			break;
		case Type::Function:
			delete val.function;
			break;
		case Type::Table:
			delete val.table;
			break;
	}
}